package com.csx.governance.traffic.route;

import com.csx.governance.traffic.core.context.TrafficMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author cuisongxu
 * @date 2023/3/18 18:49
 */
public class FilterChain<T> {

    private final Logger logger = LoggerFactory.getLogger(FilterChain.class);

    private final Class<T> instanceType;

    private final Function<T, Map<String, String>> metadataMapping;

    private final List<Filter> filters;

    private final Function<T, String> printableMapper;

    public FilterChain(Class<T> instanceType,
                       Function<T, Map<String, String>> metadataMapping,
                       List<Filter> filters) {
        this(instanceType, metadataMapping, filters, Objects::toString);
    }

    public FilterChain(Class<T> instanceType, Function<T, Map<String, String>> metadataMapping, List<Filter> filters, Function<T, String> printableMapper) {
        this.instanceType = instanceType;
        this.metadataMapping = metadataMapping;
        this.filters = filters;
        this.printableMapper = printableMapper == null ? Objects::toString : printableMapper;
    }

    public List<T> filter(List<T> originServiceInstanceList, TrafficMessage trafficMessage) {
        List<T> filteredServiceInstanceList = originServiceInstanceList;
        // TODO 需要考虑是程序内部通过定时任务发起的请求这种情况
        if(trafficMessage == null) {
            logger.debug("traffic request context is null, don't not filter ServiceInstances");
            return originServiceInstanceList;
        }

        logger.debug("before filtered service instances: {}", formatPrintableServiceInstances(originServiceInstanceList));

        for (Filter filter : filters) {
            filteredServiceInstanceList = filter.filter(filteredServiceInstanceList, metadataMapping, trafficMessage);
        }

        logger.debug("after filtered service instances: {}", formatPrintableServiceInstances(filteredServiceInstanceList));
        return filteredServiceInstanceList;
    }

    private List<String> formatPrintableServiceInstances(List<T> serviceInstances) {
        return serviceInstances.stream().map(printableMapper).collect(Collectors.toList());
    }

    public Logger getLogger() {
        return logger;
    }

    public Class<T> getInstanceType() {
        return instanceType;
    }

    public Function<T, Map<String, String>> getMetadataMapping() {
        return metadataMapping;
    }
}
